// yfs client.  implements FS operations using extent and lock server
#include "yfs_client.h"
#include "extent_client.h"
#include "extent_server.h"
#include <sstream>
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


yfs_client::yfs_client(std::string extent_dst, std::string lock_dst)
{
  ec = new extent_client(extent_dst);
  lc = new lock_client(lock_dst);
}

yfs_client::inum
yfs_client::n2i(std::string n)
{
  std::istringstream ist(n);
  unsigned long long finum;
  ist >> finum;
  return finum;
}

std::string
yfs_client::filename(inum inum)
{
  printf("yfs:filename\n");
  std::ostringstream ost;
  ost << inum;
  return ost.str();
}

bool
yfs_client::isfile(inum inum)
{
  printf("yfs:isfile\n");
  if(inum & 0x80000000)
    return true;
  return false;
}

bool
yfs_client::isdir(inum inum)
{
  printf("yfs:isdir\n");
  return ! isfile(inum);
}

int
yfs_client::getfile(inum inum, fileinfo &fin)
{
  printf("yfs:getfile\n");
  int r = OK;


  printf("getfile %016llx\n", inum);
  extent_protocol::attr a;
  if (ec->getattr(inum, a) != extent_protocol::OK) {
    r = IOERR;
    goto release;
  }

  fin.atime = a.atime;
  fin.mtime = a.mtime;
  fin.ctime = a.ctime;
  fin.size = a.size;
  printf("getfile %016llx -> sz %llu\n", inum, fin.size);

 release:

  return r;
}

int
yfs_client::getdir(inum inum, dirinfo &din)
{
  printf("yfs:getdir\n");
  int r = OK;


  printf("getdir %016llx\n", inum);
  extent_protocol::attr a;
  if (ec->getattr(inum, a) != extent_protocol::OK) {
    r = IOERR;
    goto release;
  }
  din.atime = a.atime;
  din.mtime = a.mtime;
  din.ctime = a.ctime;

 release:
  return r;
}

int yfs_client::put(inum parent, inum id, std::string buf, fileinfo &info){
  std::string contents;
  extent_protocol::attr a;
  printf("yfs: put\n");

  ec->get(parent, contents);

  // check if file is already in directory
  if(contents.find(buf) != std::string::npos){
    printf("file is in directory\n");
    return IOERR;
  }
  
  // add file to directory
  char* buffer;
  sprintf(buffer, "%s %s ", buf.c_str(), filename(id).c_str());
  contents.append(std::string(buffer));
  
  ec->put(parent, contents);
  ec->put(id, "");

  info.atime = a.atime;
  info.ctime = a.ctime;
  info.mtime = a.mtime;
  info.size = a.size;

  return OK;
  
}


int yfs_client::get(inum id, std::string &buf){
  printf("yfs:get\n");
  if(ec->get(id, buf) == extent_protocol::OK)
    return OK;
  else
    return NOENT;
}

int yfs_client::readdir(inum id, std::string &buf){
  printf("yfs:readdir\n");
  if(ec->get(id, buf) == extent_protocol::OK)
    return OK;
  else
    return NOENT;
}

int yfs_client::open(inum id, std::string &buf){
  printf("yfs:open\n");
  if(isfile(id)){
    if(ec->get(id, buf) == extent_protocol::OK)
      return OK;
    else
      return NOENT;
  }
  else {
    return NOENT;
  }
}

int yfs_client::read(inum id, std::string &buf){
  printf("yfs:read\n");
  if(ec->get(id, buf) == extent_protocol::OK)
    return OK;
  else
    return NOENT;
}

int yfs_client::getattr(inum id, extent_protocol::attr &a){
  printf("yfs client: getattr\n");
  if(ec->getattr(id, a) == extent_protocol::OK)
    return OK;
  else
    return NOENT;
}

int yfs_client::set(inum id, struct stat *attr){
  if(isfile(id)){
    std::string buffer;
    extent_protocol::attr a;
    if(ec->get(id, buffer) == extent_protocol::OK &&
       ec->getattr(id, a) == extent_protocol::OK){

      if(a.size > attr->st_size)
	buffer = buffer.substr(0, attr->st_size);
      else
	buffer.append(attr->st_size - a.size, '\0');
      
      if(ec->put(id, buffer) == extent_protocol::OK)
	return OK;
      else 
	return NOENT;
    }else {
      return NOENT;
    }
  }
  else {
    return NOENT;
  }
}

int yfs_client::remove(inum id){
  printf("yfs_client : remove\n");
  if(ec->remove(id) == extent_protocol::OK){
    return OK;
  }  else{
    return NOENT;
  }
}

int yfs_client::place(inum id, std::string buf){
  printf("yfs_client : place\n");
  if(ec->put(id, buf) == extent_protocol::OK)
    return OK;
  else
    return NOENT;
}


int yfs_client::acquire(inum id){
  printf("id to acquire: %llu\n", id);
  if (lc->acquire(id) == lock_protocol::OK){
    return OK;
  } else {
    return NOENT;
  }
}

int yfs_client::release(inum id){
  printf("id to release: %llu\n", id);
  if(ec->flush(id) == extent_protocol::OK){
    printf("successful flush\n");
  }
  else{
    printf("bummer no flush\n");
  }
  if (lc->release(id) == lock_protocol::OK){ 
    return OK;
  } else {
    return NOENT;
  }
  
}
